package cn.langpy.disroute.core;


import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executor;

/**
 * Chang Zhang
 */
public class Route {

    public static boolean isInit() {
        return RouteContext.isInit();
    }

    public static void init(String packagePath) {
        RouteContext.init(packagePath);
    }

    public static void init() {
        RouteContext.init();
    }

    public static void close() {
        RouteContext.close();
    }


    private Executor executor = RoutePool.getPool();
    private RouteCallback callback;
    private String context;
    private List<String> contexts;
    private List<RouteFilter> filters = new ArrayList<>();
    private Object param;
    private Boolean async = false;

    public Route() {
    }

    public <T> Route(String context, T param) {
        this.context = context;
        this.param = param;
    }

    public Route executor(Executor executor) {
        this.executor = executor;
        return this;
    }

    public Route callback(RouteCallback callback) {
        this.callback = callback;
        return this;
    }


    public Route context(String context) {
        this.context = context;
        return this;
    }

    public Route context(Class context) {
        this.context = context.getSimpleName();
        return this;
    }

    public Route contexts(List<String> contexts) {
        this.contexts = contexts;
        return this;
    }

    public Route filter(RouteFilter filter) {
        filters.add(filter);
        return this;
    }

    public Route async(boolean async) {
        this.async = async;
        return this;
    }

    public <T> Route param(T param) {
        this.param = param;
        return this;
    }


    public static Route build() {
        return new Route();
    }

    public <R> R dispatch() {
        for (RouteFilter filter : filters) {
            if (!filter.accept(param)) {
                RouteResult routeResult = new RouteResult<Object,R>();
                routeResult.setStartTime(LocalDateTime.now());
                routeResult.setParam(param);
                routeResult.setResult(null);
                routeResult.setFiltered(true);
                routeResult.setEndTime(LocalDateTime.now());
                if (callback!=null) {
                    RoutePool.getPool().execute(()-> callback.callback(routeResult));
                }
                return null;
            }
        }
        if (this.contexts == null) {
            if (this.async) {
                return RouteContext.dispatchAsync(executor, context, param, callback);
            } else {
                return RouteContext.dispatch(context, param, callback);
            }
        } else {
            List results = new ArrayList<>();
            for (String context : this.contexts) {
                if (this.async) {
                    RouteContext.dispatchAsync(executor, context, param, callback);
                } else {
                    Object result = RouteContext.dispatch(context, param, callback);
                    results.add(result);
                }
            }
            return (R) results;
        }

    }

//    @Deprecated
//    public static <T, R> R dispatch(T arg) {
//        String context = "context";
//        return dispatch(context, arg);
//    }

    public static <T, R> R dispatch(String context, T param) {
        return RouteContext.dispatch(context, param,null);
    }

    public static <T, R> R dispatch(Class context, T param) {
        return RouteContext.dispatch(context.getSimpleName(), param,null);
    }


}
